<?php

namespace App\Jobs;

use App\Models\Common\Constant;
use App\Models\Invoice\Invoice;
use App\Models\Invoice\Platform\ChinaUms;
use App\Models\Invoice\Subject;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Psr\Log\LoggerInterface;

class ReverseInvoice implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;


    protected $order;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(Model $order)
    {
        $this->order = $order;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $order = $this->order;
        $exceptionContent = "订单({$order->order_title}:{$order->order_code}])发票红冲失败:";

        try {

            if (!$issuedInvoice = Invoice::where('parking_lot_id', $order->parking_lot_id)->where('paid_code', $order->paid_code)->where('status', Invoice::STATUS_SUCCESS)->orderBy('updated_at', 'DESC')->first()) {
                throw new \Exception($exceptionContent . '未找到开票记录');
            }

            if ($issuedInvoice->type !== Invoice::TYPE_ISSUED) {
                throw new \Exception($exceptionContent . '最后一次的发票记录不为开票记录');
            }

            $reversedInvoice = Invoice::create([
                'parking_lot_id' => $order->parking_lot_id,
                'related_id' => $order->id,
                'related_code' => $order->order_code,
                'paid_code' => $order->paid_code,
                'related_type' => get_class($order),
                'source' => Constant::SOURCE_ADMIN,
                'app_user_id' => strval($order->app_user_id),
                'type' => Invoice::TYPE_REVERSED,
                'tag' => -1,
                'original_id' => $issuedInvoice->id,
                'status' => Invoice::STATUS_FAILED
            ]);

            if (!$reversedInvoice) {
                throw new \Exception($exceptionContent . '生成发票红冲记录失败');
            }

            if (!$subject = Subject::where('parking_lot_id', $order->parking_lot_id)->where('enabled', true)->first()) {
                throw new \Exception($exceptionContent . '车场未配置可用的开票主体');
            }

            switch ($subject->type) {
                case Subject::TYPE_CHINA_UMS:
                default:
                    $chinaUms = new ChinaUms($subject);
                    $chinaUms->heartBeat()->fire();
                    $response = $chinaUms->reverse(['order_code' => $order->order_code, 'paid_at' => $order->paid_at])->fire();

                    $resultCode = \Arr::get($response, 'resultCode');
                    $errMsg = \Arr::get($response, 'errMsg');
                    $status = \Arr::get($response, 'status');

                    if (!in_array($status, [ChinaUms::STATUS_REVERSED, ChinaUms::STATUS_REVERSING], true)) {
                        throw new \Exception($exceptionContent . '发票的状态不是已红冲状态(' . $status . ')');
                    }

                    if ($resultCode === 'SUCCESS') {

                        if ($status === ChinaUms::STATUS_REVERSING) {
                            sleep(2);
                            $response = $chinaUms->query(['order_code' => $order->order_code, 'paid_at' => $order->paid_at])->fire();
                        }

                        $reversedInvoice->xml_dat = [
                            'xml' => strval(\Arr::get($response, 'xml')),
                            'preview_url' => strval(\Arr::get($response, 'xmlPreviewUrl')),
                            'url' => strval(\Arr::get($response, 'xmlUrl'))
                        ];

                        $reversedInvoice->pdf_dat = [
                            'pdf' => strval(\Arr::get($response, 'pdf')),
                            'preview_url' => strval(\Arr::get($response, 'pdfPreviewUrl')),
                            'url' => strval(\Arr::get($response, 'pdfUrl'))
                        ];

                        $reversedInvoice->ofd_dat = [
                            'ofd' => strval(\Arr::get($response, 'ofd')),
                            'preview_url' => strval(\Arr::get($response, 'ofdPreviewUrl')),
                            'url' => strval(\Arr::get($response, 'ofdUrl'))
                        ];

                        $reversedInvoice->qr_code_dat = [
                            'qr_code' => strval(\Arr::get($response, 'qrCodeId')),
                            'preview_url' => strval(\Arr::get($response, 'qrCode')),
                            'url' => strval(\Arr::get($response, 'issueQrCode'))
                        ];

                        $reversedInvoice->amount = -floatval(\Arr::get($response, 'totalPrice'));
                        $reversedInvoice->total_amount = -floatval(\Arr::get($response, 'totalPriceIncludingTax'));
                        $reversedInvoice->tax_amount = -floatval(\Arr::get($response, 'totalTax'));

                        try {
                            $reverseDate = Carbon::parse(\Arr::get($response, 'reverseDate'))->toDateTimeString();
                        } catch (\Throwable $exception) {
                            $reverseDate = now()->toDateTimeString();
                        }

                        $reversedInvoice->triggered_at = $reverseDate;
                        $reversedInvoice->cipher_code = strval(\Arr::get($response, 'reverseCipherCode'));
                        $reversedInvoice->check_code = strval(\Arr::get($response, 'reverseCheckCode'));
                        $reversedInvoice->good_details = @json_decode(strval(\Arr::get($response, 'goodsDetail')), true) ?: [];
                        $reversedInvoice->code = strval(\Arr::get($response, 'reverseInvoiceCode'));
                        $reversedInvoice->number = strval(\Arr::get($response, 'reverseInvoiceNo'));
                        $reversedInvoice->status = Invoice::STATUS_SUCCESS;
                    } else {
                        $reversedInvoice->err_msg = $errMsg;
                    }
                    $reversedInvoice->save();
                    break;
            }
        } catch (\Throwable $exception) {
            app(LoggerInterface::class)->error($exception->getMessage(), ['exception' => $exception, 'trigger' => '发票红冲脚本']);
        }
    }
}
